package com.example.dicomviewer.reconstruction;

import android.opengl.GLES20;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import android.util.Log;

import com.example.dicomviewer.core.DataArray;
import com.example.dicomviewer.reconstruction.shapes.Lung;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import static android.opengl.GLES30.GL_TEXTURE_3D;

/**
 * Created by Kiven on 2018/4/9.
 * Details:
 */

public class MyGLRenderer implements GLSurfaceView.Renderer {
    private static final String TAG = "MyGLRenderer";
    private Lung lung;
    private int textureId;
    private float[] cameraPos = {0f, (float) Math.sqrt(6) / 2f, 0f};
    private double[] cameraAngle = {-Math.PI / 2f, 0};
    private float[] up = {0f, 0f, -1f};
    private double radius = Math.sqrt(6) / 2f;
    private double scale = 1f;

    public double getScale() {
        return scale;
    }

    public void setScale(double scale) {
        this.scale = scale;
    }

    public float[] getCameraPos() {
        return cameraPos;
    }

    public void setUp(float xAngl) {
        up = new float[]{0f, 0f, -1f};
    }

    public void setCameraAngle(double a, double b) {
        // a为0时，向量和x轴重合 , 逆时针方向为正
        // b为0时，向量在XoY面上，指向屏幕外的方向
        /*  --------> y
         * |
         * |
         * |
         * |
         * V
         * x
         * */
        cameraAngle[0] = a;
        cameraAngle[1] = b;
        fixCameraPos();
    }

    private void fixCameraPos() {
        double a = cameraAngle[0];
        double b = cameraAngle[1];
        cameraPos[0] = (float) (radius * Math.cos(b) * Math.sin(a));
        cameraPos[1] = (float) (radius * Math.cos(b) * Math.cos(a));
        cameraPos[2] = (float) (radius * Math.sin(b));
    }

    public double[] getCameraAngle() {
        return cameraAngle;
    }

    public double getRadius() {
        return radius;
    }

    public void reloadTexure() {
        this.textureId = createTexture();
        lung.onDraw(this.textureId, this.cameraPos, this.up, (float) this.scale);
    }

    public static int createTexture() {
        Log.d(TAG, "begin createTexture");
        int[] textures = new int[1];
        GLES30.glGenTextures(1, textures, 0);
        int textureId = textures[0];
        Log.d(TAG, "begin binding");
        GLES30.glBindTexture(GL_TEXTURE_3D, textureId);
        GLES30.glTexParameterf(GLES30.GL_TEXTURE_3D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);
        // 网上说这里如果是 GL_LINEAR ，那么采样结果会是0
        GLES30.glTexParameterf(GLES30.GL_TEXTURE_3D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
        GLES30.glTexParameterf(GLES30.GL_TEXTURE_3D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
        GLES30.glTexParameterf(GLES30.GL_TEXTURE_3D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);
        GLES30.glTexParameterf(GLES30.GL_TEXTURE_3D, GLES30.GL_TEXTURE_WRAP_R, GLES30.GL_CLAMP_TO_EDGE);
        Log.d(TAG, "end binding");

        Log.d(TAG, "begin trans to Buffer");
        // 将数组元素转化为 Buffer
        DataArray dataArray = DataArray.getInstance();
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(dataArray.getFixedPixel().length);
        byteBuffer.put(dataArray.getFixedPixel());
        byteBuffer.position(0);
        byteBuffer.order(ByteOrder.nativeOrder());
//        FloatBuffer floatBuffer = byteBuffer.asFloatBuffer();
        Log.d(TAG, "end trans to Buffer");

        Log.d(TAG, "byteBuffer length: " + dataArray.getFixedPixel().length);
        Log.d(TAG, "before fixed array length * 4: " + dataArray.getPixel().length * 4);
        Log.d(TAG, "Width: " + dataArray.getWidth());
        Log.d(TAG, "Hight: " + dataArray.getHight());
        Log.d(TAG, "SliceSize: " + dataArray.getSliceSize());

        Log.d(TAG, "begin texImage3D");
        // 绑定纹理和数据 RGBA 四个值都要用 byte 表示
        GLES30.glTexImage3D(GL_TEXTURE_3D, 0, GLES30.GL_RGBA8, dataArray.getWidth(), dataArray.getHight(), dataArray.getSliceSize(), 0, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, byteBuffer);
        Log.d(TAG, "end texImage3D");

        Log.d(TAG, "end createTexture");
        Log.d(TAG, "textureId: " + textureId);
        return textureId;
    }

    // 一切的初始化，包括纹理的绑定，都应该在这个里面
    @Override
    public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
        Log.d(TAG, "begin onSurfaceCreated");
        GLES30.glEnable(GLES30.GL_BLEND);
        GLES30.glEnable(GLES30.GL_DEPTH_TEST);
        GLES30.glEnable(GLES30.GL_SAMPLER_3D);
        GLES30.glEnable(GL_TEXTURE_3D);
        lung = new Lung();
        this.textureId = createTexture();
//        square = new Square();
        Log.d(TAG, "end onSurfaceCreated");
    }

    // mMVPMatrix 的全称是 "Model View Projection Matrix"
//    private final float[] mMVPMatrix = new float[16];
//    private final float[] mProjectionMatrix = new float[16];
//    private final float[] mViewMatrix = new float[16];
//    private float[] mRotationMatrix = new float[16];

    @Override
    public void onSurfaceChanged(GL10 gl10, int width, int height) {
//        float ratio = (float) width / height;
        Log.d(TAG, "<onSurfaceChange>");
        // 这个投影矩阵被用于onDrawFrame()中绘制对象的坐标系
//        Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
        lung.onSurfaceChange(width, height);
        // 修复了界面刚出现时，摄像头偏转90° 的 bug
        fixCameraPos();
        lung.onDraw(this.textureId, this.cameraPos, this.up, (float) this.scale);
    }

    private float clearColor[] = new float[]{0.0f, 0.0f, 0.0f, 1.0f};

    @Override
    public void onDrawFrame(GL10 gl10) {
        Log.d(TAG, "begin onDrawFrame");
        GLES30.glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT);
        lung.onDraw(this.textureId, this.cameraPos, this.up, (float) this.scale);
//        square.onDraw(this.textureId);
        Log.d(TAG, "end onDrawFrame");
    }

    public static int loadShader(int type, String shaderCode) {

        // 创建一个顶点渲染器类型(GLES20.GL_VERTEX_SHADER)
        // 或者碎片渲染器类型(GLES20.GL_FRAGMENT_SHADER)
        int shader = GLES20.glCreateShader(type);

        // 将渲染器源码加入渲染器并编译
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);

        return shader;
    }
}
